package im.vinci.server.user.service;

import com.aliyun.openservices.ons.api.*;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.iot.model.v20160530.PubRequest;
import com.aliyuncs.iot.model.v20160530.PubResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import im.vinci.server.common.exceptions.VinciException;
import im.vinci.server.common.exceptions.error.ErrorCode;
import im.vinci.server.common.tmsg.ProducerMessage;
import im.vinci.server.common.tmsg.TransactionMessageHolder;
import im.vinci.server.user.domain.UserAddressBook;
import im.vinci.server.user.domain.UserAttention;
import im.vinci.server.user.domain.UserCounts;
import im.vinci.server.user.domain.UserInfo;
import im.vinci.server.user.persistence.UserAddressBookMapper;
import im.vinci.server.user.persistence.UserAttentionMapper;
import im.vinci.server.utils.BizTemplate;
import im.vinci.server.utils.JsonUtils;
import im.vinci.server.utils.UserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import redis.clients.jedis.*;

import javax.annotation.PostConstruct;
import java.math.BigInteger;
import java.util.*;

/**
 * Created by mayuchen on 16/8/3.
 */
@Service
public class UserAttentionService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserLoginAndBindDeviceService userLoginAndBindDeviceService;

    @Autowired
    private UserCountService userCountService;

    @Autowired
    private UserAttentionMapper userAttentionMapper;

    @Autowired
    private UserAddressBookMapper userAddressBookMapper;

    @Autowired
    private JedisPool jedisPool;

    @Value("${add_user.byGeo.expire_time:30}")
    private int addUserByGeoExpire_time;

    @Value("${ons.add_friend_f2f.topic}")
    private String vinciAsyncMsgTopic;

    @Value("${iot.vinci.headphone.productKey}")
    private long iotProductKey;

    @Autowired
    private Environment env;

    @Autowired
    private IAcsClient iotClient;

    @PostConstruct
    public void init() {
        _runRedisListenExpireKeys();
    }

    @Bean(destroyMethod = "shutdown")
    @Profile({"qaci", "prod"})
    public Consumer newUserAddAttentionF2F() {
        Properties properties = new Properties();

        properties.put(PropertyKeyConst.AccessKey, env.getRequiredProperty("ons.accessKey"));
        properties.put(PropertyKeyConst.SecretKey, env.getRequiredProperty("ons.secretKey"));
        properties.put(PropertyKeyConst.ConsumerId, env.getRequiredProperty("ons.add_friend_f2f.consumeID"));
        Consumer consumer = ONSFactory.createConsumer(properties);
        _runUserAddAttentionF2F(consumer);
        return consumer;
    }

    //接收消息,加f2f好友
    private void _runUserAddAttentionF2F(Consumer consumer) {
        consumer.subscribe(vinciAsyncMsgTopic, "addAttentionF2f", new MessageListener() {
                    @Override
                    public Action consume(Message message, ConsumeContext context) {
                        Jedis jedis = null;
                        try {
                            long uid = Long.parseLong(message.getUserProperties("uid"));
                            long targetUid = Long.parseLong(message.getUserProperties("targetUid"));
                            String sn = message.getUserProperties("sn");
                            String targetSn = message.getUserProperties("targetSn");
                            userAttentionMapper.insertUserFriend(uid, targetUid);

                            JsonNode node = JsonNodeFactory.instance.objectNode()
                                    .put("action", "add_attention_f2f.add").put("fromSn", "server")
                                    .set("data", JsonNodeFactory.instance.objectNode().put("target_uid", targetUid));

                            PubRequest pub = new PubRequest();
                            pub.setProductKey(iotProductKey);
                            pub.setMessageContent(Base64Utils.encodeToString(JsonUtils.encode2bytes(node)));
                            pub.setTopicFullName("/" + iotProductKey + "/" + sn + "/get");//消息发送给哪个topic中.
                            pub.setQos(1);//设置Qos为1，那么设备如果不在线，重新上线会收到离线消息，消息最多在Iot Hub中保存7天.
                            PubResponse response = iotClient.getAcsResponse(pub);

                            logger.info("add attention f2f send iot({}) msg:{}, and response({}):{},{}", pub.getTopicFullName(), node, response.getRequestId(), response.getSuccess(), response.getErrorMessage());

                            node = JsonNodeFactory.instance.objectNode()
                                    .put("action", "add_attention_f2f.add").put("fromSn", "server")
                                    .set("data", JsonNodeFactory.instance.objectNode().put("target_uid", uid));
                            pub = new PubRequest();
                            pub.setProductKey(iotProductKey);
                            pub.setMessageContent(Base64Utils.encodeToString(JsonUtils.encode2bytes(node)));
                            pub.setTopicFullName("/" + iotProductKey + "/" + targetSn + "/get");//消息发送给哪个topic中.
                            pub.setQos(1);//设置Qos为1，那么设备如果不在线，重新上线会收到离线消息，消息最多在Iot Hub中保存7天.
                            response = iotClient.getAcsResponse(pub);
                            logger.info("add attention f2f send iot({}) msg:{}, and response({}):{},{}", pub.getTopicFullName(), node, response.getRequestId(), response.getSuccess(), response.getErrorMessage());
                            jedis = jedisPool.getResource();
                            jedis.del("add_attention_geo_" + uid, "add_attention_geo_" + targetUid);
                            jedis.zrem("add_attention_geo", String.valueOf(uid), String.valueOf(targetUid));
                            return Action.CommitMessage;
                        } catch (NumberFormatException e) {
                            return Action.CommitMessage;
                        } catch (Exception e) {
                            logger.warn("actual add user attention f2f error and retry:", e);
                            return Action.ReconsumeLater;
                        } finally {
                            if (jedis != null) {
                                jedis.close();
                            }
                        }
                    }
                }
        );
        consumer.start();
    }

    private void _runRedisListenExpireKeys() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                jedisPool.getResource().psubscribe(new JedisPubSub() {
                    @Override
                    public void onPMessage(String pattern, String channel, String message) {
                        if ("__keyevent@0__:expired".equals(channel)) {
                            return;
                        }
                        if (message == null || !message.startsWith("add_attention_geo_")) {
                            return;
                        }
                        Jedis jedis = null;
                        String uid = message.substring("add_attention_geo_".length());
                        try {
                            jedis = jedisPool.getResource();
                            jedis.zrem("add_attention_geo", uid);
                        } catch (Exception e) {
                            //ignore
                        } finally {
                            if (jedis != null) {
                                jedis.close();
                            }
                        }
                        logger.info("add attention f2f expire:{}", message);
                    }
                }, "__keyevent@0__:expired");
            }
        }, "redisSubExpiredKey").start();

    }


    /**
     * 添加用户关注
     *
     * @return 返回关注是否成功
     */
    @Transactional
    public boolean insertUserAttention(final long userId, final long attentionUid) {
        return new BizTemplate<Boolean>("insertUserAttention") {

            @Override
            protected void checkParams() throws VinciException {
                if (StringUtils.isEmpty(userId)) {
                    throw new VinciException(ErrorCode.NEED_LOGIN, "用户为空", "用户为空");
                }
                if (StringUtils.isEmpty(attentionUid)) {
                    throw new VinciException(ErrorCode.NEED_LOGIN, "关注用户为空", "被关注用户为空");
                }
            }

            @Override
            protected Boolean process() throws Exception {
                UserInfo userInfo;
                UserAttention userAttention = new UserAttention();

                //验证被关注用户是否存在
                userInfo = userLoginAndBindDeviceService.checkUserInfo(attentionUid);
                if (userInfo == null) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_USER_NOT_FOUND
                            , String.format("被关注用户不存在:uid:%s", attentionUid), "被关注用户不存在");
                }
                if (userId == userInfo.getId()) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_INSERT_YOURSELF
                            , String.format("用户%s不能关注自己", userInfo.getId()), "不能自己关注自己");
                }
                userAttention.setUserId(userId).setAttentionUserId(userInfo.getId());
                //验证用户是否已经添加对某用户的关注
                int num = userAttentionMapper.getUserAttentionBy_user_attention_id(userId, userInfo.getId());
                if (num > 0) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_ALREADY_INSERT
                            , String.format("用户%s已被用户%s关注", userInfo.getId(), userId), "用户已被用户关注");
                }
                num = userAttentionMapper.getUserAttentionBy_user_attention_id(attentionUid, userId);
                userAttentionMapper.insertUserAttention(userAttention);
                if (!userCountService.adjustAttentionCount(userId, userInfo.getId(), false)) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_REACH_MAX_COUNT, "关注到达最大", "关注到达最大");
                }
                if (num > 0) {
                    userAttentionMapper.updateUserFriendFlag(userId, attentionUid);
                }
                return true;
            }
        }.execute();
    }

    /**
     * 删除用户关注
     *
     * @return 返回删除用户关注是否成功
     */
    @Transactional
    public boolean deleteUserAttention(final long userId, final long attentionUid) {
        return new BizTemplate<Boolean>("deleteUserAttention") {

            @Override
            protected void checkParams() throws VinciException {
                if (StringUtils.isEmpty(userId)) {
                    throw new VinciException(ErrorCode.NEED_LOGIN, "用户为空", "用户为空");
                }
                if (StringUtils.isEmpty(attentionUid)) {
                    throw new VinciException(ErrorCode.NEED_LOGIN, "关注用户为空", "被关注用户为空");
                }
            }

            @Override
            protected Boolean process() throws Exception {
                UserInfo userInfo;

                //验证被关注用户是否存在
                userInfo = userLoginAndBindDeviceService.checkUserInfo(attentionUid);
                if (userInfo == null) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_USER_NOT_FOUND
                            , String.format("被关注用户不存在:uid:%s", attentionUid), "被关注用户不存在");
                }

                //验证用户是否已经添加对某用户的关注
                int num = userAttentionMapper.getUserAttentionBy_user_attention_id(userId, userInfo.getId());
                if (num == 0) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_NOT_EXIST
                            , String.format("用户%s未被用户%s关注", userInfo.getId(), userId), "用户未被用户关注,无法取消关注");
                }
                try {
                    userAttentionMapper.deleteUserAttention(userId, userInfo.getId());
                    userCountService.adjustAttentionCount(userId, userInfo.getId(), true);
                    userAttentionMapper.removeUserFriendFlag(userId, attentionUid);
                } catch (Exception e) {
                    logger.error(userId + " " + userInfo.getId() + ", 数据库错误", e);
                    throw new VinciException(ErrorCode.USER_ATTENTION_INSERT_ERROR, "删除数据项错误" + e.getMessage(), "删除用户关注错误");
                }
                return true;
            }
        }.execute();
    }

    public List<UserInfo> getBothFriendList(final long userId) {
        return new BizTemplate<List<UserInfo>>("getBothFriendList") {

            @Override
            protected void checkParams() throws VinciException {

            }

            @Override
            protected List<UserInfo> process() throws Exception {
                return null;
            }
        }.execute();
    }

    /**
     * 获取一个用户所有关注列表
     */
    public List<Long> getUserAttentionListOnly(final long userId) {
        List<Long> list = userAttentionMapper.getUserAttetionListOnly(userId);
        if (list == null) {
            list = Lists.newArrayList();
        }
        list.add(userId);
        return list;
    }

    /**
     * 获取用户关注列表对应的用户信息表
     *
     * @return 返回用户关注列表对应的用户信息表
     */
    public List<UserAttention> getUserAttentionerList(final long userId, final long lastAttentionId, final long pageSize, final boolean isBoth) {
        return new BizTemplate<List<UserAttention>>("getUserAttentionList") {

            @Override
            protected void checkParams() throws VinciException {
                if (userId <= 0) {
                    throw new VinciException(ErrorCode.NEED_LOGIN, "用户为空", "用户为空");
                }
                if (lastAttentionId < 0) {
                    throw new VinciException(ErrorCode.ARGUMENT_ERROR, "页面偏移参数错误", "页面偏移参数错误");
                }
            }

            @Override
            protected List<UserAttention> process() throws Exception {
                //验证用户是否存在
                UserInfo userInfo = userLoginAndBindDeviceService.checkUserInfo(userId);
                if (userInfo == null) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_USER_NOT_FOUND
                            , String.format("用户不存在:uid:%s", userId), "用户不存在");
                }
                try {
                    List<UserAttention> userAttentionList;
                    //先查询关注表

                    if (isBoth) {
                        if (lastAttentionId == 0) {
                            userAttentionList = userAttentionMapper.getUserAttentionListBoth(userId, pageSize);
                        } else {
                            userAttentionList = userAttentionMapper.getLaterAttentionIdBoth(userId, lastAttentionId, pageSize);
                        }
                    } else {
                        if (lastAttentionId == 0) {
                            userAttentionList = userAttentionMapper.getUserAttentionList(userId, pageSize);
                        } else {
                            userAttentionList = userAttentionMapper.getLaterAttentionId(userId, lastAttentionId, pageSize);
                        }
                    }

                    List<UserAttention> resultList = mergeUserInfo(userAttentionList, true);
                    if (!CollectionUtils.isEmpty(resultList)) {
                        Collections.sort(resultList, new Comparator<UserAttention>() {
                            @Override
                            public int compare(UserAttention o1, UserAttention o2) {
                                if (o1.getId() > o2.getId()) {
                                    return -1;
                                } else if (o1.getId() == o2.getId()) {
                                    return 0;
                                } else {
                                    return 1;
                                }
                            }
                        });
                    }

                    return resultList;

                } catch (Exception e) {
                    logger.error(userId + ", 数据库错误", e);
                    throw new VinciException(ErrorCode.USER_ATTENTION_INSERT_ERROR, "获取用户关注列表错误对应的用户信息表错误" + e.getMessage(), "获取用户关注列表错误,请重试");
                }
            }
        }.execute();
    }


    /**
     * 获取用户粉丝列表
     *
     * @return 返回用户粉丝列表
     */
    public List<UserAttention> getUserFollowerList(final long attentionUid, final long lastAttentionId, final long pageSize) {
        return new BizTemplate<List<UserAttention>>("getUserFollowList") {
            @Override
            protected void checkParams() throws VinciException {
                if (StringUtils.isEmpty(attentionUid)) {
                    throw new VinciException(ErrorCode.NEED_LOGIN, "用户为空", "用户为空");
                }
                if (lastAttentionId < 0) {
                    throw new VinciException(ErrorCode.ARGUMENT_ERROR, "页面偏移参数错误", "页面偏移参数错误");
                }
                if (pageSize > 50 || pageSize < 0) {
                    throw new VinciException(ErrorCode.ARGUMENT_ERROR, "传入的页面大小过大或者页面参数错误", "传入的页面大小过大或者页面参数错误");
                }

            }

            @Override
            protected List<UserAttention> process() throws Exception {


                //验证用户是否存在
                UserInfo userInfo = userLoginAndBindDeviceService.checkUserInfo(attentionUid);
                if (userInfo == null) {
                    throw new VinciException(ErrorCode.USER_ATTENTION_USER_NOT_FOUND
                            , String.format("用户不存在:uid:%s", attentionUid), "用户不存在");
                }

                try {
                    List<UserAttention> userFollowers;
                    if (lastAttentionId == 0) {
                        userFollowers = userAttentionMapper.getUserFollowList(userInfo.getId(), pageSize);
                    } else {
                        userFollowers = userAttentionMapper.getLaterFollowList(userInfo.getId(), lastAttentionId, pageSize);
                    }
                    if (CollectionUtils.isEmpty(userFollowers)) {
                        return Collections.emptyList();
                    }
                    userFollowers = mergeUserInfo(userFollowers, false);
                    List<UserInfo> userInfos = Lists.newArrayListWithCapacity(userFollowers.size());
                    for (UserAttention attention : userFollowers) {
                        userInfos.add(attention.getUserInfo());
                    }
                    //查询我有没有关注我的粉丝
                    checkIsAttention(UserContext.getUserInfo().getId(), userInfos);

                    return userFollowers;

                } catch (Exception e) {
                    logger.error(userInfo.getId() + ", 数据库错误", e);
                    throw new VinciException(ErrorCode.USER_ATTENTION_INSERT_ERROR, "获取用户粉丝列表错误" + e.getMessage(), "获取用户粉丝列表错误");
                }
            }
        }.execute();
    }

    public Collection<UserInfo> checkIsAttention(long uid, Collection<UserInfo> userInfos) {
        if (CollectionUtils.isEmpty(userInfos)) {
            return userInfos;
        }
        Set<Long> attentions = Sets.newHashSet(getUserAttentionListOnly(uid));
        for (UserInfo info : userInfos) {
            if (info != null && (attentions.contains(info.getId()) || info.getId() == uid)) {
                info.setAttention(true);
            }
        }
        return userInfos;
    }

    public Set<Long> checkIsFollower(long uid, Collection<Long> uids) {
        return userAttentionMapper.getIsFollowerList(uid, uids);
    }


    /**
     * 加入到索引中,判断附近有没有加好友的人,如果没有就结束,并等待其他人进入这个方法加好友
     */
    @Transactional
    public long addAttentionF2F(long uid, String sn, double longitude, double latitude) {
        return new BizTemplate<Long>("addAttentionF2F") {

            @Override
            protected void checkParams() throws VinciException {

            }

            @Override
            protected Long process() throws Exception {
                long now = System.currentTimeMillis();
                long targetUid = 0L;
                String targetSn = null;
                Jedis jedis = null;
                try {
                    jedis = jedisPool.getResource();
                    //加一个带过期时间的key
                    String ret = jedis.setex("add_attention_geo_" + uid, addUserByGeoExpire_time, String.valueOf(now) + "," + sn);
                    if (StringUtils.isEmpty(ret) || !ret.contains("OK")) {
                        throw new VinciException(ErrorCode.USER_ATTENTION_SEARCH_RADIUS_ERROR, "redis set ex error:" + ret, "加好友失败");
                    }
                    //加入到geo map中
                    Long lr = jedis.geoadd("add_attention_geo", longitude, latitude, String.valueOf(uid));
                    if (lr == null) {
                        throw new VinciException(ErrorCode.USER_ATTENTION_SEARCH_RADIUS_ERROR, "redis add geo error:" + lr, "加好友失败");
                    }
                    //找到附近的人
                    List<GeoRadiusResponse> responses = jedis.georadiusByMember("add_attention_geo", String.valueOf(uid), 50, GeoUnit.M);
                    if (logger.isDebugEnabled()) {
                        logger.debug("get geo radius by member {} response:{}", uid, JsonUtils.encode(responses));
                    }
                    if (responses == null || responses.size() == 0) {
                        return 0L;
                    }
                    List<Long> userids = Lists.newArrayListWithCapacity(responses.size());
                    List<String> useridKeys = Lists.newArrayListWithCapacity(responses.size());
                    List<Double> distances = Lists.newArrayListWithCapacity(responses.size());
                    for (GeoRadiusResponse response : responses) {
                        if (response != null && response.getMemberByString() != null) {
                            if (response.getMemberByString().equalsIgnoreCase(String.valueOf(uid))) {
                                continue;
                            }
                            long tuid = org.apache.commons.lang3.math.NumberUtils.toLong(response.getMemberByString(), 0);
                            if (tuid > 0L) {
                                userids.add(tuid);
                                useridKeys.add("add_attention_geo_" + tuid);
                                distances.add(response.getDistance());
                            }
                        }
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("add f2f attention find some uid:{}", userids);
                    }
                    if (userids.size() == 0) {
                        return 0L;
                    }
                    //获取带过期时间的key,如果key不存在了需要清理掉
                    List<String> times = jedis.mget(useridKeys.toArray(new String[useridKeys.size()]));
                    if (logger.isDebugEnabled()) {
                        logger.debug("add attention f2f get user apply times:{}", times);
                    }
                    double maxScore = Double.MAX_VALUE;
                    List<String> expireGeoUser = Lists.newArrayListWithCapacity(userids.size());
                    for (int i = 0; i < userids.size(); i++) {
                        long tuid = userids.get(i);
                        String time = times.get(i);
                        if (time == null) {
                            expireGeoUser.add(String.valueOf(tuid));
                            continue;
                        }
                        long t = Long.parseLong(time.substring(0, time.indexOf(',')));
                        String sn = time.substring(time.indexOf(',') + 1);
                        double score = (now - t) * distances.get(i);
                        if (logger.isDebugEnabled()) {
                            logger.debug("add attention f2f, get {} and {} distance: {}, and now:{} time:{}, score:{}; " +
                                            "and maxScore:{}, targetUid:{}, sn:{}",
                                    tuid, uid, now, t, score, maxScore, targetUid, targetSn);
                        }
                        if (score < maxScore) {
                            try {
                                targetUid = tuid;
                                targetSn = sn;
                                maxScore = score;
                            } catch (Exception e) {
                                //ignore
                            }
                        }
                    }
                    if (expireGeoUser.size() > 0) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("add attention f2f remove expire key:{}", expireGeoUser);
                        }
                        jedis.zrem("add_attention_geo", expireGeoUser.toArray(new String[expireGeoUser.size()]));
                    }
                } catch (Exception e) {
                    throw new VinciException(e, ErrorCode.USER_ATTENTION_SEARCH_RADIUS_ERROR, "redis error:" + e.toString(), "加好友失败");
                } finally {
                    if (jedis != null)
                        jedis.close();
                }
                if (targetUid > 0L) {
                    ProducerMessage msg = new ProducerMessage(vinciAsyncMsgTopic, "addAttentionF2f");
                    msg.putUserProperties("uid", String.valueOf(uid));
                    msg.putUserProperties("targetUid", String.valueOf(targetUid));
                    msg.putUserProperties("sn", sn);
                    msg.putUserProperties("targetSn", targetSn);

                    TransactionMessageHolder.insertMessage(msg);
                }
                return targetUid;
            }
        }.execute();
    }

    @Transactional
    public int uploadUserAddressBook(final long uid , List<UserAddressBook> list) {
        return new BizTemplate<Integer>("uploadUserAddressBook") {

            @Override
            protected void checkParams() throws VinciException {

            }

            @Override
            protected Integer process() throws Exception {
                userAddressBookMapper.delete(uid);
                return userAddressBookMapper.batchInsert(uid,list);
            }
        }.execute();
    }

    public List<UserInfo> getFriendsFromAddressBook(final long uid) {
        return new BizTemplate<List<UserInfo>>("getFriendsFromAddressBook") {

            @Override
            protected void checkParams() throws VinciException {

            }

            @Override
            protected List<UserInfo> process() throws Exception {
                if (userAddressBookMapper.countUserAddressBook(uid) <=0) {
                    return Collections.emptyList();
                }
                List<Map> list =  userAddressBookMapper.getFriendsInAddressBook(uid);
                List<Long> uids = Lists.newArrayListWithExpectedSize(list.size());
                Map<Long,String> maps = Maps.newHashMap();
                for (Map m : list) {
                    long id = ((BigInteger) m.get("id")).longValue();
                    if (id == uid) continue;
                    uids.add(id);
                    maps.put(id,(String) m.get("name"));
                }
                Map<Long, UserInfo> userInfoMap = userLoginAndBindDeviceService.getUserInfoMap(uids);
                List<UserInfo> userInfos = Lists.newArrayListWithCapacity(userInfoMap.size());
                Set<Long> isAttentionSet = userAttentionMapper.getIsAttentionList(uid,uids);


                for (long id : uids) {
                    if (userInfoMap.containsKey(id)) {
                        UserInfo info = userInfoMap.get(id);
                        info.setAttention(isAttentionSet.contains(id));
                        info.setAddressBookName(maps.get(id));
                        userInfos.add(info);
                    }
                }
                return userInfos;
            }
        }.execute();
    }

    @Transactional
    public boolean addAttentionUidInAddressBook(final long uid , final long attentionUid) {
        return new BizTemplate<Boolean>("addAttentionUidInAddressBook") {

            @Override
            protected void checkParams() throws VinciException {

            }

            @Override
            protected Boolean process() throws Exception {
                try {
                    boolean b = insertUserAttention(uid, attentionUid);
                    if (b) {
                        if (!userAddressBookMapper.addNewFriendMsg(uid, attentionUid)) {
                            throw new VinciException(ErrorCode.INTERNAL_SERVER_ERROR, "数据库错误", "数据库错误");
                        }
                        userCountService.adjustNewFriendMessageUnreadCount(attentionUid,1);
                    }
                    return b;
                }catch (VinciException e) {
                    if (e.getErrorCode() == ErrorCode.USER_ATTENTION_ALREADY_INSERT) {
                        return true;
                    }
                }
                return false;
            }
        }.execute();
    }

    @Transactional
    public List<UserAttention> getAttentionApplyMsg(final long uid) {
        return new BizTemplate<List<UserAttention>>("getAttentionApplyMsg") {

            @Override
            protected void checkParams() throws VinciException {

            }

            @Override
            protected List<UserAttention> process() throws Exception {
                UserCounts userCounts = userCountService.getUserCount(uid);
                List<UserAttention> list = userAddressBookMapper.getNewFriendMsgList(uid);
                userCountService.adjustNewFriendMessageUnreadCount(uid, -userCounts.getApplyNewFriendUnreadCount());
                return mergeUserInfoWithApplyFriends(uid, list);
            }
        }.execute();
    }

    public boolean cancelAttentionF2F(final long uid) {
        return new BizTemplate<Boolean>("cancelAttentionF2F") {

            @Override
            protected void checkParams() throws VinciException {
            }

            @Override
            protected Boolean process() throws Exception {
                Jedis jedis = null;
                try {
                    jedis = jedisPool.getResource();
                    jedis.del("add_attention_geo_" + uid);
                    jedis.zrem("add_attention_geo", String.valueOf(uid));
                } catch (Exception e) {
                    logger.warn("cancel attention f2f error:", e);
                    return false;
                } finally {
                    if (jedis != null)
                        jedis.close();
                }
                return true;
            }
        }.execute();
    }

    private List<UserAttention> mergeUserInfo(List<UserAttention> attentions, boolean isAttention) {
        if (attentions == null || CollectionUtils.isEmpty(attentions)) {
            return Collections.emptyList();
        }
        List<Long> userIds = Lists.newArrayListWithCapacity(attentions.size());
        //再查询对应的用户信息表
        for (UserAttention userAttention : attentions) {
            if (isAttention) {
                userIds.add(userAttention.getAttentionUserId());
            } else {
                userIds.add(userAttention.getUserId());
            }
        }
        Map<Long, UserInfo> map = userLoginAndBindDeviceService.getUserInfoMap(userIds);
        Iterator<UserAttention> iterator = attentions.iterator();
        while (iterator.hasNext()) {
            UserAttention attention = iterator.next();
            UserInfo userInfo = map.get(isAttention ? attention.getAttentionUserId() : attention.getUserId());
            if (userInfo == null) {
                iterator.remove();
            } else {
                attention.setUserInfo(userInfo);
                if (isAttention) {
                    userInfo.setAttention(true);
                }
            }
        }
        return attentions;
    }
    private List<UserAttention> mergeUserInfoWithApplyFriends(long uid , List<UserAttention> attentions) {
        if (attentions == null || CollectionUtils.isEmpty(attentions)) {
            return Collections.emptyList();
        }
        List<Long> userIds = Lists.newArrayListWithCapacity(attentions.size());
        //再查询对应的用户信息表
        for (UserAttention userAttention : attentions) {
            userIds.add(userAttention.getAttentionUserId());
        }
        Map<Long, UserInfo> map = userLoginAndBindDeviceService.getUserInfoMap(userIds);
        Set<Long> set = userAttentionMapper.getIsAttentionList(uid,userIds);
        Iterator<UserAttention> iterator = attentions.iterator();
        while (iterator.hasNext()) {
            UserAttention attention = iterator.next();
            UserInfo userInfo = map.get(attention.getAttentionUserId());
            if (userInfo == null) {
                iterator.remove();
            } else {
                attention.setUserInfo(userInfo);
                userInfo.setAttention(set.contains(attention.getAttentionUserId()));
            }
        }
        return attentions;
    }
}
